﻿namespace DYH.CAD.Assoc.Cmd;

public static class 直线与圆相切
{
    [CommandMethod(nameof(TestLineTangent2Circle))]
    public static void TestLineTangent2Circle()
    {
        var ed = Env.Editor;
        ObjectId lineId, cirId;

        #region 选择交互

        while (true)
        {
            var r1 = ed.GetEntity(new PromptEntityOptions("\n选择直线") { AllowNone = true });
            if (r1.Status != PromptStatus.OK)
                return;
            if (!r1.ObjectId.ObjectClass.IsDerivedFrom(RXClassEx.Line))
            {
                IFoxUtils.ShowBubbleWindow(5, "错误", "选择的不是线");
                continue;
            }

            lineId = r1.ObjectId;
            break;
        }

        while (true)
        {
            var r2 = ed.GetEntity(new PromptEntityOptions("\n选择圆") { AllowNone = true });
            if (r2.Status != PromptStatus.OK)
                return;
            if (!r2.ObjectId.ObjectClass.IsDerivedFrom(RXClassEx.Circle))
            {
                IFoxUtils.ShowBubbleWindow(5, "错误", "选择的不是圆");
                continue;
            }

            cirId = r2.ObjectId;
            break;
        }

        #endregion


        var db = lineId.Database;
        using var tr = new DBTrans(lineId.Database);
        var line = (Entity)tr.GetObject(lineId);
        var instanceFromDatabase = AssocNetwork.GetInstanceFromObject(line.OwnerId, true, true, "");
        var nw = (AssocNetwork)tr.GetObject(instanceFromDatabase, OpenMode.ForWrite);
        var ac = new AssocAction();
        var myActionBody = new LineTangent2CircleBody();
        var abId = db.AddDBObject(myActionBody);
        tr.Transaction.AddNewlyCreatedDBObject(myActionBody, true);
        var actionId = db.AddDBObject(ac);
        ac.ActionBody = abId;
        nw.AddAction(actionId, true);
        var dp1 = new AssocDependency();
        var dp1Id = db.AddDBObject(dp1);
        dp1.AttachToObject(new CompoundObjectId(lineId));
        dp1.IsReadDependency = true;
        dp1.IsWriteDependency = true;
        dp1.Order = 0;
        ac.AddDependency(dp1Id, true);
        var dp2 = new AssocDependency();
        var dp2Id = db.AddDBObject(dp2);
        dp2.AttachToObject(new CompoundObjectId(cirId));
        dp2.IsReadDependency = true;
        dp2.IsWriteDependency = true;
        dp2.Order = 1;
        ac.AddDependency(dp2Id, true);
        dp2.Close();
        dp1.Close();
        ac.Close();
    }

    public class LineTangent2CircleBody : AssocActionBody
    {
        public override void EvaluateOverride()
        {
            var assocEvaluationCallback = currentEvaluationCallback();
            if (assocEvaluationCallback.EvaluationMode() != AssocEvaluationMode.ModifyObjectsAssocEvaluationMode)
            {
                Status = AssocStatus.FailedToEvaluateAssocStatus;
                return;
            }

            if (HasAnyErasedOrBrokenDependencies())
            {
                Status = AssocStatus.ErasedAssocStatus;
                return;
            }

            using var tr = new AssocObjectTransaction(this);
            var objectIdCollection = GetDependencies(true, true);
            var dp1Id = objectIdCollection[0];
            using var dp1 = (AssocDependency)tr.GetDBObject(dp1Id, OpenMode.ForRead, false, true);
            var lineId = dp1.DependentOnObject;
            var status1 = dp1.Status;
            var dp2Id = objectIdCollection[1];
            var dp2 = (AssocDependency)tr.GetDBObject(dp2Id, OpenMode.ForRead, false, true);
            var cirId = dp2.DependentOnObject;
            var status2 = dp2.Status;
            EvaluateDependencies();
            if (status1 == AssocStatus.IsUpToDateAssocStatus && status2 == AssocStatus.IsUpToDateAssocStatus)
            {
                Status = AssocStatus.IsUpToDateAssocStatus;
                return;
            }

            if (!lineId.IsOk() ||
                !lineId.ObjectClass.IsDerivedFrom(RXClassEx.Line) ||
                !cirId.IsOk() ||
                !cirId.ObjectClass.IsDerivedFrom(RXClassEx.Circle))
            {
                Status = AssocStatus.FailedToEvaluateAssocStatus;
                return;
            }

            var line = (Line)tr.GetDBObject(lineId, OpenMode.ForWrite, false, true);
            using var cir = (Circle)tr.GetDBObject(cirId, OpenMode.ForWrite, false, true);
            var closestPointTo = line.GetClosestPointTo(cir.Center, true);
            if (status1 != AssocStatus.IsUpToDateAssocStatus)
            {
                var distance2dTo = cir.Radius = cir.Center.Distance2dTo(closestPointTo);
                if (distance2dTo == 0)
                {
                    distance2dTo = 1e-6;
                }

                cir.SetPropertiesFrom(line);
                cir.Radius = distance2dTo;
            }
            else
            {
                var clPt = line.GetClosestPointTo(cir.Center, true);
                var dir = cir.Center.GetVectorTo(clPt).OrthoProjectTo(cir.Normal).GetNormal();
                var newPt = cir.Center + dir * cir.Radius;
                line.Move(clPt, newPt);
                line.SetPropertiesFrom(cir);
            }

            Status = AssocStatus.IsUpToDateAssocStatus;
        }

        #region 克隆，未成功

        /*public override void AddMoreObjectsToDeepCloneOverride(IdMapping idMap, ObjectIdCollection additionalObjectsToClone)
        {
            var objectIdCollection = GetDependencies(true, true);
            var tr = new AssocObjectTransaction(this);
            foreach (ObjectId id in objectIdCollection)
            {
                var obj = tr.GetDBObject(id, OpenMode.ForRead, false, true);
                if (obj is AssocDependency dep)
                {
                    additionalObjectsToClone.Add(id);
                    additionalObjectsToClone.Add(dep.DependentOnObject);
                }
            }

            additionalObjectsToClone.Add(this.ObjectId);
            additionalObjectsToClone.Add(ParentAction);
        }
        public override void PostProcessAfterDeepCloneOverride(IdMapping idMap)
        {
            var tr = new AssocObjectTransaction(this);
            var objectIdCollection = GetDependencies(true, true);
            var dp1 = (AssocDependency)tr.GetDBObject(objectIdCollection[0], OpenMode.ForRead, false, true);
            var l1Id = dp1.DependentOnObject;
            var dp2 = (AssocDependency)tr.GetDBObject(objectIdCollection[1], OpenMode.ForRead, false, true);
            var c1Id = dp2.DependentOnObject;
            // 拿到新的
            var l2Id = idMap[l1Id].Value;
            var c2Id = idMap[c1Id].Value;
            if (tr.GetDBObject(l2Id, OpenMode.ForWrite, false, true) is not Line l2)
                return;
            var btr = (BlockTableRecord)tr.GetDBObject(l2.OwnerId, OpenMode.ForWrite, false, true);
            btr.AssumeOwnershipOf([l2Id, c2Id]);
        }

        public override ErrorStatus DwgOutFields(DwgFiler filer)
        {
            base.DwgOutFields(filer);
            if (this.ObjectId.IsNull || ParentAction.IsNull)
                return ErrorStatus.NotImplementedYet;

            return ErrorStatus.OK;
        }

        public override ErrorStatus DwgInFields(DwgFiler filer)
        {
            base.DwgInFields(filer);
            if (this.ObjectId.IsNull || ParentAction.IsNull)
                return ErrorStatus.NotImplementedYet;

            var readUInt32 = filer.ReadUInt16();
            return ErrorStatus.OK;
        }*/

        #endregion
    }
}